﻿using System;
using System.Collections.Generic;

using OptixDotNet;

using RayDen.Library.Components.Surface;
using RayDen.Library.Entity.Scene;

using RayDen.Optix.Engine.Components;

namespace RayDen.Optix.Engine.Scene.Factories
{

    public class MaterialFactory : OptixComponent
    {
        private Dictionary<BrdfClass, Tuple<string, string, string>> classKernelMap = new Dictionary
            <BrdfClass, Tuple<string, string, string>>()
        {
             {
                BrdfClass.Experimental,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuseEmitterCL",
                    "shadow")
            },
            {
                BrdfClass.DiffuseLambert,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },


            {
                BrdfClass.Mirror,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "glossymetal_envmap",
                    "shadow")
            },


            {
                BrdfClass.GlossyMetal,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },


            {
                BrdfClass.Glass,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "glass",
                    "glass_shadow")
            },

            {
                BrdfClass.Alloy,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\mats_specular.cu.ptx",
                    "alloy",
                    "shadow")
            },



             {
                BrdfClass.Distribution,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },
            
             {
                BrdfClass.ArchGlass,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },

            
             {
                BrdfClass.Measured,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },

            
             {
                BrdfClass.MatteMirror,
                new Tuple<string, string, string>(
                    @"G:\Git\RayDen\Engines\RayDen.Optix.Engine\Scripts\materials.cu.ptx",
                    "diffuse_all",
                    "shadow")
            },
        };


        public MaterialFactory(Context ctx)
            : base(ctx)
        {
        }

        public OptixMaterialInfo CreateMaterial(MaterialInfo mi)
        {
            var result = new OptixMaterialInfo()
            {
                Name = mi.Name.ToLower(),
                Info = mi,
                Type = BrdfClassNameMapper.GetMaterialClass(mi)
            };
            result.Node = new Material(context);
            var type = result.Type;
            result.Node.SetSurfaceProgram(0, new SurfaceProgram(context, RayHitType.Closest, classKernelMap[type].Item1, classKernelMap[type].Item2));
            result.Node.SetSurfaceProgram(1, new SurfaceProgram(context, RayHitType.Any, classKernelMap[type].Item1, classKernelMap[type].Item3));
            /*
            switch (result.Type)
            {
                case BrdfClass.DiffuseLambert:
                    

                    break;

            }*/
            return result;
        }

        public OptixMaterialInfo CreateMaterial(MaterialInfo mi, BrdfClass type)
        {
            var result = new OptixMaterialInfo()
            {
                Name = mi.Name.ToLower(),
                Info = mi,
                Type = type
            };
            result.Node = new Material(context);
            result.Node.SetSurfaceProgram(0, new SurfaceProgram(context, RayHitType.Closest, classKernelMap[result.Type].Item1, classKernelMap[result.Type].Item2));
            result.Node.SetSurfaceProgram(1, new SurfaceProgram(context, RayHitType.Any, classKernelMap[result.Type].Item1, classKernelMap[result.Type].Item3));
            /*
            switch (result.Type)
            {
                case BrdfClass.DiffuseLambert:
                    

                    break;

            }*/
            return result;
        }
    }
}
